package com.example.lock.controller;

import com.example.lock.entity.LockInfo;
import com.example.lock.zk.impl.ZkLockImpl;
import com.example.lock.mapper.UserMapper;
import com.example.util.TranslationUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * @Description: 任务逻辑处理层
 * @Author: mingtian
 * @CreateDate: 2020/12/5 15:37
 * @Version: 1.0
 */
@Component
public class ZkTaskService {

    /**
     * 打印日志
     */
    private Logger logger = LoggerFactory.getLogger(ZkTaskService.class);

    @Value("${server.port}")
    private String serverPort;

    @Autowired
    private TranslationUtils translationUtils;

    @Autowired
    private ZkLockImpl zkLock;

    @Autowired
    private UserMapper userMapper;

    /**
     * 开始状态
     */
    private static String LOCK_START = "start";

    /**
     * 结束状态
     */
    private static String LOCK_STOP = "stop";

    /**
     * 存放当前 jvm 线程  key:锁的Id，value:锁得信息
     */
    private static Map<String, LockInfo> lockInfoMap = new ConcurrentHashMap<String, LockInfo>();

    /**
     * 声明定时任务线程池
     */
    private ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();

    /**
     * 定时执行 续命使用
     */
    public ZkTaskService() {
        //scheduledExecutorService.scheduleAtFixedRate(new DetectionAlgorithm(), 0, 5, TimeUnit.HOURS);
    }

    /**
     * 检测续命线程
     */
    class DetectionAlgorithm implements Runnable {

        @Override
        public void run() {
            lockInfoMap.forEach((k, lockInfo) -> {
                if (LOCK_START.equals(lockInfo.getState())) {
                    // 1.主动关闭连接
                    lockInfo.getLock().releaseLock();
                    // 2.回滚事务
                    lockInfo.getTranslationUtils().rollBack(lockInfo.getTransactionStatus());
                    // 3.阻塞线程
                    lockInfo.getLockThread().interrupt();
                    // 4.避免重复检索(移除)
                    lockInfoMap.remove(k);
                }
            });
        }
    }


    /**
     * 测试 ZK 羊群效应的时候 应该注释 @Scheduled(cron = "0/3 * * * * ?")
     */
  //  @Scheduled(cron = "0/3 * * * * ?")
    public void taskService() {
        try {
            logger.info("开始执行任务,serverPort:{}", serverPort);
            // 获取锁
            boolean lock = zkLock.getLock();
            if (lock) {
                // 提交事务
                TransactionStatus begin = translationUtils.begin();
                // 记录锁id
                String lockId = UUID.randomUUID().toString();
                lockInfoMap.put(lockId, new LockInfo(lockId, Thread.currentThread(), LOCK_START, zkLock, translationUtils, begin));
                userMapper.insert("明天", 23);
                logger.info("[{}]正在执行业务逻辑...", serverPort);
                // 模拟超时时间
//                Thread.sleep(500000);
                // 提交事务
                translationUtils.commit(begin);
                lockInfoMap.put(lockId, new LockInfo(lockId, Thread.currentThread(), LOCK_STOP, zkLock));
                // 释放锁
                zkLock.releaseLock();
                logger.info("任务执行完成,serverPort:{}", serverPort);
                return;
            }
            logger.error("获取锁失败,不执行业务逻辑");
        } catch (Exception e) {
            logger.error("errorInfo:{}", e.getMessage());
            // 回滚事务
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            // 释放锁
            zkLock.releaseLock();
        }
    }
}

